import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.animation import FuncAnimation
import cv2

class DynamicVisualizer:
    def __init__(self):
        self.input_image = None
        self.kernel_type = None
        self.fig = None
        self.ax1 = None
        self.ax2 = None
        self.im1 = None
        self.im2 = None
        self.rect = None
        self.text = None
        self.feature_map = None
        self.input_size = None
        self.kernel_size = None
        self.output_size = None
        # 设置图片清晰度
        plt.rcParams['figure.dpi'] = 100
        # 设置字体为SimHei（黑体），可以根据系统中已有的中文字体进行修改
        plt.rcParams['font.sans-serif'] = ['SimHei']
        # 解决负号显示问题
        plt.rcParams['axes.unicode_minus'] = False
    def load_image(self, input_image):
        """
        加载图像指令
        用途：导入本地图像文件
        参数：图像路径
        返回值：结果存入变量
        """
        # img = cv2.imread(img_path)
        # img = cv2.resize(img, (80, 80))
        # img = img.astype(np.float32) / 255.0
        # input_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换为灰度图像
        self.input_image = input_image


    def set_kernel(self, kernel_type):
        """
        定义卷积核指令
        用途：定义卷积核，可放入下拉框选择（卷积核类型可选：锐化核、纹理检测核、运动模糊核、边缘检测核）
        参数：卷积核的类型
        返回值：存入变量kernel
        """

        if kernel_type == 'sharpen':        # 锐化(中心权重高，通过削减周围像素值来突出当前像素的细节)
            kernel = np.array([[-1, -1, -1], 
                                [-1,  8, -1], 
                                [-1, -1, -1]]) 
        elif kernel_type == 'texture':      # 纹理（提取重复或规律性结构的特征）—— 线检测核，突出对角线方向的纹理结构
            kernel = np.array([[2, -1, -1], 
                                [-1, 3, -1], 
                                [-1, -1, 2]])
        elif kernel_type == 'dynamic':  # 运动模糊核（对水平方向像素进行平均，模拟水平运动模糊）
            kernel = np.array([[1/3, 1/3, 1/3], 
                            [0, 0, 0], 
                            [0, 0, 0]])
        elif kernel_type == 'edge':         # 边缘检测 Laplacian算子
            kernel = np.array([[0, 1, 0], 
                            [1, -4, 1], 
                            [0, 1, 0]])
        else:
            raise ValueError("Invalid kernel type")
        self.kernel_type = kernel
        return kernel
    def calculate_sizes(self,input_image):
        self.input_size = input_image.shape[0]
        self.kernel_size = self.kernel_type.shape[0]
        self.output_size = self.input_size - self.kernel_size + 1

    def create_canvas(self,input_image):
        self.fig, (self.ax1, self.ax2) = plt.subplots(1, 2, figsize=(10, 6))
        self.im1 = self.ax1.imshow(input_image,cmap='gray')
        self.ax1.set_title("原始图像转换后的灰度图像", fontsize='15')
        self.ax1.axis('off')

        # self.rect = patches.Rectangle((0, 0), self.kernel_size, self.kernel_size, linewidth=6, edgecolor='r', facecolor='none')
        # self.ax1.add_patch(self.rect)
        # self.text = self.ax1.text(0, 0, '', ha='center', va='center', color='white', fontsize=5)
        self.rect = patches.Rectangle((0, 0), self.kernel_size, self.kernel_size, linewidth=6, edgecolor='r', facecolor='none')  # 实心矩形
        self.ax1.add_patch(self.rect)
        self.text = self.ax1.text(0, 0, '', ha='center', va='center', color='white', fontsize=18)  # 更大的字体

        for i in range(self.input_size + 1):
            self.ax1.plot([i - 0.5, i - 0.5], [-0.5, self.input_size - 0.5], color='black', linewidth=0.5)
            self.ax1.plot([-0.5, self.input_size - 0.5], [i - 0.5, i - 0.5], color='black', linewidth=0.5)

        self.feature_map = np.zeros((self.output_size, self.output_size))
        self.im2 = self.ax2.imshow(self.feature_map, vmin=-1, vmax=1)
        self.ax2.set_title("特征图", fontsize='15')
        self.ax2.axis('off')


    def update(self, frame):
        i, j = divmod(frame, self.output_size)
        sub_matrix = self.input_image[i:i + self.kernel_size, j:j + self.kernel_size]
        conv_result = np.sum(sub_matrix * self.kernel_type)

        self.rect.set_xy((j - 0.5, i - 0.5))
        self.text.set_position((j + (self.kernel_size - 1) / 2, i + (self.kernel_size - 1) / 2))
        self.text.set_text(f'{conv_result:.2f}')

        return self.im1, self.rect, self.text

    def update2(self, frame):
        i, j = divmod(frame, self.output_size)
        if i == 0 and j == 0:
            self.feature_map.fill(0)

        sub_matrix = self.input_image[i:i + self.kernel_size, j:j + self.kernel_size]
        conv_result = np.sum(sub_matrix * self.kernel_type)
        self.feature_map[i, j] = conv_result

        self.im2.set_data(self.feature_map)

        return self.im2,

    def show_animation(self,img_path,interval):
        """
        演示卷积操作过程指令
        用途：动画呈现卷积操作过程
        参数：输入图像；卷积核
        返回值：无
        """
        self.input_image = img_path
        self.calculate_sizes(img_path)
        self.create_canvas(img_path)
        
        ani = FuncAnimation(self.fig, self.update, frames=self.output_size * self.output_size, blit=True, repeat=True, interval=interval)
        ani2 = FuncAnimation(self.fig, self.update2, frames=self.output_size * self.output_size, blit=True, repeat=True, interval=interval)
        plt.show()
        plt.close('all')

# # 示例调用
# if __name__ == '__main__':
#     visualizer = DynamicVisualizer()
#     visualizer.load_image('19.png')
#     visualizer.define_kernel('dynamic')
#     visualizer.show_animation()